'''
Languages supported by Microsoft Visual Studio and Microsoft SDKs.
'''

from __future__ import with_statement

import subprocess

from host.helpers import program_files_x86
from os_helpers import LocalCwd
from . import _base, _lang

NAME = "Microsoft Visual Studio"

# Supported Visual Studio versions (currently just restricted to what I've
# tested on my development machine)
SUPPORTED_VSTUDIO_VERSIONS = [ ('9.0', 2008), ('10.0', 2010), ('11.0', 2012) ]

def vstudio_architectures(host):
    """
    Gets the list of supported Visual Studio architectures (as parameters to
    vcvarsall.bat) for host.
    
    vcvarsall.bat also supports x86_amd64 and x86_ia64; however, there's little
    point to using a cross compiler if we can't execute its results. 
    """
    result = []
    env_arch = [ host.getenv('PROCESSOR_ARCHITECTURE'), 
                 host.getenv('PROCESSOR_ARCHITEW6432') ]
    if 'x86' in env_arch:
        result.append('x86')
    if 'AMD64' in env_arch:
        result.append('amd64')
    if 'IA64' in env_arch:
        result.append('ia64')
    return result

def check(host, binary, language, environment_list, create_args):
    """
    Checks a host for each supported Visual Studio version for a particular
    language, and adds any found to environment_list.
    """
    # TODO: Need spaces around cmdline_binary_bat here???
    for internal_ver, human_ver in SUPPORTED_VSTUDIO_VERSIONS:
        cmdline_bat = host.path_join(program_files_x86(host), 
                                     'Microsoft Visual Studio ' + internal_ver, 
                                     'VC',
                                     'vcvarsall.bat')
        if host.path_exists(cmdline_bat):
            for arch in vstudio_architectures(host):
                description = 'Microsoft Visual %s' % language.name
                cmdline_binary_bat = host.path_join(host.work_dir, 'vstudio_%s_%s.cmd' % (internal_ver, binary))
                host.file_write(cmdline_binary_bat, 'wt',
                                '@call "%s" %s > nul:\n@%s %%*' % (cmdline_bat, arch, binary))
                environment_list[language.name][description].append(VStudioEnvironment(language, host, cmdline_binary_bat, 'Visual Studio %s (%s)' % (human_ver, arch), *create_args))

def configure_language(host_list, environment_list, language, binary, *create_args):
    """
    Configures the requested language by checking each host in host_list and
    adding detected environments to environment_list.
    """
    for host in host_list:
        if 'nt' not in host.os_name_list:
            continue
        check(host, binary, language, environment_list, create_args)

def configure(host_list, environment_list):
    configure_language(host_list, environment_list, _lang.Cpp, 'cl', '/Fe')
    configure_language(host_list, environment_list, _lang.C, 'cl', '/Fe')
    configure_language(host_list, environment_list, _lang.CSharp, 'csc', '/out:')

class VStudioEnvironment(_base.Environment):
    """
    An environment for one of the languages supported by Visual Studio or the
    Microsoft SDKs.
    """
    
    has_arguments = True
    
    def __init__(self, language, host, path, version, output_flag):
        self.language = language
        self.host = host
        self.path = path
        self.version = version
        self.exe_suffix = '.exe'        
        self._output_flag = output_flag

    def compile(self, filename, output):
        """
        Compiles the given source file and sends the result to output.
        """
        file_dirname = self.host.path_dirname(filename)
        file_basename = self.host.path_basename(filename)
        with LocalCwd(file_dirname, self.host):
            # For compatibility with the C# compiler, we list the output flag
            # first.
            vs = self.host.popen([self.path,
                                  self._output_flag + self.exe_filename_for(file_basename),
                                  file_basename], 
                                 stderr=subprocess.STDOUT)
            stdoutdata = vs.communicate()[0]
            output.write(stdoutdata)

        return vs.returncode == 0
